import 'package:flutter/material.dart';

import 'package:flutter_application_test/calendar/widgets/custom_page_view.dart';
import 'package:flutter_application_test/calendar/widgets/day_widget.dart';
import 'package:flutter_application_test/calendar/widgets/notification.dart';

/// 日期视图
class MonthWidget extends StatefulWidget {
  /// 背景颜色
  final Color bgColor;

  /// 当前显示的 DateTime
  final DateTime dateTime;

  /// 选中的某个日期
  final DateTime? selDateTime;

  /// 需要显示的总月数
  final int monthTotal;

  /// 是否在这个月显示上个月的日期
  final bool showLastDay;

  /// 滚动控制器
  final PageController? pageController;

  /// 切换回调
  final void Function(DateTime dateTime, int index)? onChangeMonth;

  /// 切换结束回调
  final void Function(DateTime dateTime, int index)? onChangeEndMonth;

  /// 选择日期回调
  final ValueChanged<DateTime>? onSelectedDay;

  const MonthWidget({
    Key? key,
    this.bgColor = Colors.white,
    required this.dateTime,
    required this.monthTotal,
    this.selDateTime,
    this.showLastDay = false,
    this.pageController,
    this.onChangeMonth,
    this.onChangeEndMonth,
    this.onSelectedDay,
  })  : assert(monthTotal > 1),
        super(key: key);

  @override
  State<MonthWidget> createState() => _MonthWidgetState();
}

class _MonthWidgetState extends State<MonthWidget> {
  /// 开始的年份
  late final int _startYear;

  /// 开始的月份
  late final int _startMonth;

  @override
  void initState() {
    super.initState();
    _startYear = widget.dateTime.year;
    _startMonth = widget.dateTime.month;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: widget.bgColor,
      child: CustomPageView.builder(
        controller: widget.pageController,
        itemCount: widget.monthTotal,
        itemBuilder: (context, index) {
          int month = index + _startMonth;

          DateTime currentDT = DateTime(_startYear, month, 1);
          return _Month(
            dateTime: currentDT,
            selDateTime: widget.selDateTime,
            onSelectedDay: widget.onSelectedDay,
          );
        },
        onPageChanged: (index) {
          int month = index + _startMonth;

          DateTime currentDT = DateTime(_startYear, month, 1);
          widget.onChangeMonth?.call(currentDT, index);
        },
        onPageEndChanged: (index) {
          int month = index + _startMonth;

          DateTime currentDT = DateTime(_startYear, month, 1);
          widget.onChangeEndMonth?.call(currentDT, index);
        },
      ),
    );
  }
}

/// 当前显示的月份视图
class _Month extends StatelessWidget {
  /// 当前显示的 DateTime
  final DateTime dateTime;

  /// 当前选中的 DateTime
  final DateTime? selDateTime;

  /// 选择日期回调
  final ValueChanged<DateTime>? onSelectedDay;

  const _Month({
    Key? key,
    required this.dateTime,
    this.selDateTime,
    this.onSelectedDay,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return NotificationListener<CalendarNotification>(
      onNotification: (notification) {
        DateTime selDT = DateTime(dateTime.year, dateTime.month, notification.selectDay);

        onSelectedDay?.call(selDT);

        return true;
      },
      child: Column(
        children: getDays(),
      ),
    );
  }

  /// 获取日期
  List<Row> getDays() {
    /// 存放一组 day
    List<Row> daysRow = <Row>[];

    /// 存放天小部件
    List<DayWidget> daysWidget = [];

    int year = dateTime.year;
    int month = dateTime.month;

    /// 这个月多少天
    /// 计算下个月1号的前一天是几号，得出结果。
    /// DateTime(year, month + 1, 0) 这里day设置0：上一个月的最后一天是几号；
    /// 例子：-1：上个月倒二天是几号；1：这个月的1号（系统会自动计算）
    int daysInMonth = month > DateTime.monthsPerYear ? DateTime(year + 1, 1, 0).day : DateTime(year, month + 1, 0).day;

    /// 日 一 二 三 四 五 六 (这个月第一天是星期几(1号是星期几)，weekday：当前星期几(7...1))
    int firstWeekdatInMonth = DateTime(year, month, 1).weekday;

    /// int day = 1 - firstWeekdatInMonth：这个月1号前面预留数(上个月衔接到这月的上个月的号数)
    /// day = 0；标识上个月最后一天
    for (int day = 1 - firstWeekdatInMonth; day <= daysInMonth + firstWeekdatInMonth; day++) {
      DateTime moment = DateTime(year, month, day);

      /// 是否今天
      bool isToday = moment.year == DateTime.now().year && moment.month == DateTime.now().month && moment.day == DateTime.now().day;

      /// 是否周末
      bool isWeekend = moment.weekday == DateTime.sunday || moment.weekday == DateTime.saturday;

      /// 是否被选中
      bool isSelected = selDateTime != null ? ((dateTime.year == selDateTime!.year && dateTime.month == selDateTime!.month) ? selDateTime!.day == day : false) : false;

      /// 创建 day 小部件
      var widget = DayWidget(
        day: (day <= 0 || day > daysInMonth) ? -1 : moment.day,
        isToday: isToday,
        isWeekend: isWeekend,
        isSelected: isSelected,
      );
      daysWidget.add(widget);

      /// 每七天为一组
      if ((day + firstWeekdatInMonth) % DateTime.daysPerWeek == 0 || day == (daysInMonth + firstWeekdatInMonth)) {
        daysRow.add(Row(children: List<DayWidget>.from(daysWidget)));
        daysWidget.clear();
      }
    }

    return daysRow;
  }
}
